home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 21 / Cream of the Crop 21 (Terry Blount) (October 1996).iso / os2 / vsoup11.zip / nntpcl.cc < prev    next >
C/C++ Source or Header  |  1996-09-02  |  16KB  |  715 lines

  1. //  $Id: nntpcl.cc 1.14 1996/09/02 13:28:02 hardy Exp $
  2. //
  3. //  This progam/module was written by Hardy Griech based on ideas and
  4. //  pieces of code from Chin Huang (cthuang@io.org).  Bug reports should
  5. //  be submitted to rgriech@ibm.net.
  6. //
  7. //  This file is part of soup++ for OS/2.  Soup++ including this file
  8. //  is freeware.  There is no warranty of any kind implied.  The terms
  9. //  of the GNU Gernal Public Licence are valid for this piece of software.
  10. //
  11. //  NNTP client routines
  12. //
  13.  
  14.  
  15. #include <assert.h>
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <time.h>
  20.  
  21. #include "mts.hh"
  22. #include "nntp.hh"
  23. #include "nntpcl.hh"
  24. #include "socket.hh"
  25.  
  26.  
  27.  
  28. //
  29. //  is this a misfeature of GCC, is there a better way to do it??
  30. //
  31. #define STR2(x) #x
  32. #define STR(x)  STR2(x)
  33.  
  34.  
  35.  
  36. static TSemaphor cntSema;     // static in class tut nicht (gcc2.7.0)
  37. static TProtCounter bytesRcvd;
  38.  
  39.  
  40.  
  41. //--------------------------------------------------------------------------------
  42.  
  43.  
  44.  
  45. TNntp::TNntp( void )
  46. {
  47. #ifdef TRACE_ALL
  48.     printfT( "TNntp::TNntp()\n" );
  49. #endif
  50.     tmpF = NULL;
  51.     tmpN = NULL;
  52.     xrefHook  = NULL;
  53.     killQHook = NULL;
  54.     actGroup = xstrdup("");
  55.     selGroup = xstrdup("");
  56.     user     = xstrdup("");
  57.     passwd   = xstrdup("");
  58.     strcpy( lastErrMsg, "unknown error condition" );
  59. }   // TNntp::TNntp
  60.  
  61.  
  62.  
  63. TNntp::~TNntp()
  64. {
  65. #ifdef TRACE_ALL
  66.     printfT( "TNntp::~TNntp()\n" );
  67. #endif
  68.     close( 0 );
  69. ////    delete actGroup;
  70. ////    delete selGroup;
  71.     //// delete user;
  72.     //// delete passwd;
  73. }   // TNntp::~TNntp
  74.  
  75.  
  76.  
  77. void TNntp::setHelper( void (*xref)(const char *xrefLine),
  78.                int (*killQ)(const char *groupName, const char *headerLine ) )
  79. {
  80.     xrefHook  = xref;
  81.     killQHook = killQ;
  82. }   // TNntp::setHelper
  83.  
  84.  
  85.  
  86. TNntp::Res TNntp::request( const char *cmd, char *reply, size_t replySize,
  87.                int expReply )
  88. //
  89. //  Send a request to NNTP server and check the result (cmd must not end with \n)
  90. //  If the server request authentication, the AUTHINFO procedure according to
  91. //  RFC977-extension will be executed.
  92. //
  93. {
  94.     int retcode;
  95.     int loopCnt;
  96.  
  97.     *reply = '\0';
  98.     loopCnt = 0;
  99.     for (;;) {
  100.     //
  101.     //  three retries for the command
  102.     //
  103.     if (loopCnt++ >= 3) {
  104.         strcpy( lastErrMsg,"nntp server is in a loop requesting AUTHINFO..." );
  105.         return nok;
  106.     }
  107.  
  108.     //
  109.     //  transmit the command & fetch the result
  110.     //
  111.     puts( cmd );
  112.     if (gets(reply,replySize) == NULL) {
  113.         sprintfT( lastErrMsg,"%s:  no reply", cmd );
  114.         return nok;
  115.     }
  116.     bytesRcvd += strlen(reply);
  117.     if (reply[0] == CHAR_FATAL) {
  118.         sprintfT( lastErrMsg,"%s:  fatal(%s)", cmd,reply );
  119.         return nok;
  120.     }
  121.  
  122.     //
  123.     //  if return code != ERR_NOAUTH, we are done (-> check the result)
  124.     //
  125.     retcode = atoi(reply);
  126.     if (retcode != ERR_NOAUTH)
  127.         break;
  128.  
  129. #ifndef NDEBUG
  130.     fprintfT( stderr,"authentication requested\n" );
  131. #endif
  132.     //
  133.     //  otherwise do the authentication
  134.     //
  135.     printf( "AUTHINFO USER %s\n",user );
  136.     if (gets(reply,replySize) == NULL) {
  137.         strcpy( lastErrMsg,"AUTHINFO USER:  no reply" );
  138.         return nok;
  139.     }
  140.     retcode = atoi(reply);
  141.     if (retcode == OK_AUTH)
  142.         continue;
  143.     if (retcode != NEED_AUTHDATA) {
  144.         sprintfT( lastErrMsg,"AUTHINFO USER:  %s",reply );
  145.         return nok;
  146.     }
  147.     
  148.     printf( "AUTHINFO PASS %s\n",passwd );
  149.     if (gets(reply,replySize) == NULL) {
  150.         strcpy( lastErrMsg,"AUTHINFO PASS:  no reply" );
  151.         return nok;
  152.     }
  153.     retcode = atoi(reply);
  154.     if (retcode != OK_AUTH) {
  155.         sprintfT( lastErrMsg,"AUTHINFO PASS:  %s",reply );
  156.         return nok;
  157.     }
  158. #ifndef NDEBUG
  159.     fprintfT( stderr,"authentication ok\n" );
  160. #endif
  161.     }
  162.  
  163.     if (retcode != expReply) {
  164.     sprintfT( lastErrMsg,"%s:  %s", cmd,reply );
  165.     return nok;
  166.     }
  167.     return ok;
  168. }   // TNntp::request
  169.  
  170.  
  171.  
  172. TNntp::Res TNntp::open( const char *nntpServer, const char *nntpUser,
  173.             const char *nntpPasswd )
  174. {
  175.     char buf[NNTP_STRLEN];
  176.     int  response;
  177.  
  178. #ifdef TRACE_ALL
  179.     printfT( "TNntp::open(%s)\n",nntpServer );
  180. #endif
  181.     readOnly = 0;
  182.     xstrdup(   &user,nntpUser );
  183.     xstrdup( &passwd,nntpPasswd );
  184.  
  185.     if (nntpServer == NULL  ||  *nntpServer == '\0') {
  186.     strcpy( lastErrMsg,"no news server defined" );
  187.     return nok;
  188.     }
  189.  
  190.     if (TSocket::open( nntpServer,"nntp","tcp" ) < 0) {
  191.     strcpy( lastErrMsg,"cannot open socket" );
  192.     return nok;
  193.     }
  194.  
  195.     if (gets(buf, sizeof(buf)) == NULL) {
  196.     strcpy( lastErrMsg,"connect:  no reply" );
  197. #ifdef DEBUG
  198.     printfT( "TNntp::open():  socket: %s\n",buf );
  199. #endif
  200.     return nok;
  201.     }
  202.     else {
  203.     response = atoi(buf);
  204.     switch (response) {
  205.  
  206.     case OK_NOPOST:
  207.         readOnly = 1;
  208.         break;
  209.         
  210.     case OK_CANPOST:
  211.         break;
  212.         
  213.     case ERR_ACCESS:
  214.         sprintfT( lastErrMsg,"connect:  no permission, %s",buf );
  215.         return nok;
  216.         
  217.     default:
  218.         sprintfT( lastErrMsg,"connect:  ill response, %s",buf );
  219. #ifdef DEBUG
  220.         printfT( "TNntp::open():  illresp: %s\n",buf );
  221. #endif
  222.         return nok;
  223.     }
  224.     }
  225.  
  226.     //
  227.     // This is for INN (result is ignored)
  228.     //
  229.     request( "MODE READER",buf,sizeof(buf),OK_CANPOST );
  230. #ifdef DEBUG_ALL
  231.     printfT( "TNntp::open():  antwort auf mode reader: %s\n",buf );
  232. #endif
  233.  
  234.     //
  235.     //  create temporary file
  236.     //
  237.     if (tmpF == NULL) {
  238.     sysSema.Request();
  239.     tmpN = tempnam(NULL,"soup");
  240.     tmpF = fopenT(tmpN,"w+b");
  241.     sysSema.Release();
  242.     if (tmpF == NULL) {
  243.         sprintfT( lastErrMsg,"create of '%s' failed",tmpN );
  244.         return nok;
  245.     }
  246.     }
  247.     return ok;
  248. }   // TNntnp::open
  249.  
  250.  
  251.  
  252. void TNntp::close( int sendQuit )
  253. {
  254. #ifdef TRACE_ALL
  255.     printfT( "TNntp::close(%d)\n",sendQuit );
  256. #endif
  257.     if (sendQuit) {
  258.     char buf[100];
  259.  
  260. #ifdef TRACE_ALL
  261.     printfT( "TNntp::close(): QUIT\n" );
  262. #endif
  263.     request( "QUIT",buf,sizeof(buf), OK_GOODBYE );
  264.     TSocket::close();
  265.     }
  266.  
  267.     //
  268.     //  remove temporary file
  269.     //
  270.     if (tmpF != NULL) {
  271.     fcloseT( tmpF );
  272.     tmpF = NULL;
  273.     removeT( tmpN );
  274.     //// delete tmpN;
  275.     tmpN = NULL;
  276.     }
  277. }   // TNntp::close
  278.  
  279.  
  280.  
  281. const char *TNntp::getLastErrMsg( void )
  282. {
  283.     return lastErrMsg;
  284. }   // TNntp::getLastErrMsg
  285.  
  286.  
  287.  
  288. TNntp::Res TNntp::getNewGroups( const char *nntpTimeFile, int changeFile )
  289. //
  290. //  - send listing of new newsgroups as an email
  291. //  - add new newsgroups to newsrc
  292. //
  293. {
  294.     char oldTime[80], nntpTime[80], buf[NNTP_STRLEN];
  295.     FILE *dateF;
  296.     int getall;
  297.     char *p;
  298.  
  299. #ifdef TRACE
  300.     printfT( "getNewGroups()\n" );
  301. #endif
  302.  
  303.     //
  304.     //  get current date/time from NNTP server
  305.     //
  306.     if (request("DATE",buf,sizeof(buf),INF_DATE) == ok)
  307.     sscanfT( buf+4, "%s", nntpTime );
  308.     else {
  309.     time_t now = time(NULL);
  310.     strftime( nntpTime, sizeof(nntpTime), "%Y%m%d%H%M%S", gmtime(&now) );
  311.     }
  312.     
  313.     //
  314.     //  Get last date/time we checked for new newsgroups.
  315.     //
  316.     getall = 0;
  317.     if ((dateF = fopenT(nntpTimeFile, "r")) != NULL) {
  318.     fgetsT( oldTime, sizeof(oldTime), dateF);
  319.     fclose( dateF );
  320.     }
  321.     else {
  322.     //
  323.     //  This is probably the first we checked for new newsgroups.
  324.     //  yes -> get all available newsgroups!
  325.     //
  326.     memset( oldTime,0,sizeof(oldTime) );
  327.     getall = 1;
  328.     }
  329.  
  330.     //
  331.     //  Request new newsgroups.
  332.     //
  333.     {
  334.     char cmd[100];
  335.  
  336.     if (getall)
  337.         strcpy( cmd,"LIST" );
  338.     else
  339.         sprintfT( cmd,"NEWGROUPS %-6.6s %-6.6s GMT", oldTime+2, oldTime+8);
  340.     if (request(cmd,buf,sizeof(buf),getall ? OK_GROUPS : OK_NEWGROUPS) != ok)
  341.         return nok;
  342.     }
  343.  
  344.     ftruncateT( tmpF,0L );
  345.     while (gets(buf, sizeof(buf)) != NULL) {
  346. #ifdef DEBUG_ALL
  347.     printfT( "rcv: %s\n",buf );
  348. #endif
  349.     bytesRcvd += strlen(buf)+1;
  350.  
  351.     if (buf[0] == '.')
  352.         break;
  353.     if ((p = strchr(buf, ' ')) != NULL)
  354.         *p = '\0';
  355.  
  356.     fputsT( buf,tmpF );
  357.     fputcT( '\n',tmpF );
  358.     }
  359.  
  360.     //
  361.     //  Save current date/time.
  362.     //
  363.     if (changeFile) {
  364.     if ((dateF = fopenT(nntpTimeFile,"w")) != NULL) {
  365.         fprintfT( dateF,"%s\n",nntpTime );
  366.         fcloseT(dateF);
  367.     }
  368.     }
  369.     return ok;
  370. }   // TNntp::getNewGroups
  371.  
  372.  
  373.  
  374. TNntp::Res TNntp::getOverview( long first, long last )
  375. //
  376. //  Attention:  those overview lines are sometimes VERY long (ref